package com.frank.auth.domain.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.frank.auth.common.enums.RedisKeyPrefixEnum;
import com.frank.auth.domain.bo.AuthUserBo;
import com.frank.auth.domain.constants.AuthConstant;
import com.frank.auth.domain.convert.AuthUserBoConvert;
import com.frank.auth.domain.redis.RedisUtil;
import com.frank.auth.domain.service.UserDomainService;
import com.frank.auth.infra.basic.entity.*;
import com.frank.auth.infra.basic.service.*;
import com.frank.common.enums.StateEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Frank Zou
 * @version v0.0.1
 * @date 2024/2/9
 * @description
 */
@Service
public class UserDomainServiceImpl implements UserDomainService {

    private final AuthUserService authUserService;

    private final AuthRoleService authRoleService;

    private final AuthUserRoleService authUserRoleService;

    private final AuthRolePermissionService authRolePermissionService;

    private final AuthPermissionService authPermissionService;

    private final RedisUtil redisUtil;


    public UserDomainServiceImpl(AuthUserService authUserService, AuthRoleService authRoleService, AuthUserRoleService authUserRoleService, AuthRolePermissionService authRolePermissionService, AuthPermissionService authPermissionService, RedisUtil redisUtil) {
        this.authUserService = authUserService;
        this.authRoleService = authRoleService;
        this.authUserRoleService = authUserRoleService;
        this.authRolePermissionService = authRolePermissionService;
        this.authPermissionService = authPermissionService;
        this.redisUtil = redisUtil;
    }

    private final String salt = "jc club";


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AuthUserBo authUserBo) {
        AuthUser authUser = AuthUserBoConvert.INSTANCE.convertBoToEntity(authUserBo);
        LambdaQueryWrapper<AuthUser> authUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        authUserLambdaQueryWrapper.eq(AuthUser::getUserName, authUser.getUserName());
        int count = authUserService.count(authUserLambdaQueryWrapper);
        if (count > 0) {
            return true;
        }
        if (StringUtils.isNotBlank(authUser.getPassword())) {
            authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(), salt));
        }
        authUser.setStatus(StateEnum.ENABLED.getCode());
        boolean saveResult = authUserService.save(authUser);
        // 建立一个初步的角色关联
        LambdaQueryWrapper<AuthRole> roleQueryWrapper = new LambdaQueryWrapper<>();
        roleQueryWrapper.eq(AuthRole::getRoleKey, AuthConstant.NORMAL_USER);
        AuthRole roleResult = authRoleService.getOne(roleQueryWrapper);
        AuthUserRole authUserRole = new AuthUserRole();
        authUserRole.setUserId(authUser.getId());
        authUserRole.setRoleId(roleResult.getId());
        authUserRoleService.save(authUserRole);
        // 把当前用户的角色和权限都保存到 Redis 中
        // 1、获取用户的角色信息保存到 Redis
        String roleKey = redisUtil.buildKey(RedisKeyPrefixEnum.ROLE_KEY.getKey(), authUser.getUserName());
        List<String> roleKeyList = new LinkedList<>();
        roleKeyList.add(roleResult.getRoleKey());
        redisUtil.set(roleKey, JSON.toJSONString(roleKeyList));
        // 2、获取用户的权限信息保存到 Redis
        LambdaQueryWrapper<AuthRolePermission> rolePermissionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        rolePermissionLambdaQueryWrapper.eq(AuthRolePermission::getRoleId, roleResult.getId());
        List<AuthRolePermission> authRolePermissionList = authRolePermissionService.list(rolePermissionLambdaQueryWrapper);
        List<Long> permissionIdList = authRolePermissionList.stream().map(AuthRolePermission::getPermissionId).collect(Collectors.toList());
        List<String> permissionKeyList = authPermissionService.listByIds(permissionIdList).stream().map(AuthPermission::getPermissionKey).collect(Collectors.toList());
        String permissionKey = redisUtil.buildKey(RedisKeyPrefixEnum.PERMISSION_KEY.getKey(), authUser.getUserName());
        redisUtil.set(permissionKey, JSON.toJSONString(permissionKeyList));
        return saveResult;
    }

    @Override
    public Boolean update(AuthUserBo authUserBo) {
        AuthUser authUser = AuthUserBoConvert.INSTANCE.convertBoToEntity(authUserBo);
        // 如果有任何的更新，都要与缓存进行同步修改
        return authUserService.updateById(authUser);
    }

    @Override
    public Boolean delete(Long userId) {
        return authUserService.removeById(userId);
    }

    @Override
    @Transactional
    public SaTokenInfo doLogin(String captcha) {
        String buildKey = redisUtil.buildKey("login", "captcha", captcha);
        String openId = redisUtil.get(buildKey);
        if (openId == null) {
            throw new IllegalArgumentException("验证码错误");
        }
        AuthUserBo authUserBo = new AuthUserBo();
        authUserBo.setUserName(openId);
        this.register(authUserBo);
        StpUtil.login(openId);
        return StpUtil.getTokenInfo();
    }

    @Override
    public AuthUserBo getUserInfo(String captcha) {
        LambdaQueryWrapper<AuthUser> authUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        authUserLambdaQueryWrapper.eq(AuthUser::getUserName, captcha);
        AuthUser one = authUserService.getOne(authUserLambdaQueryWrapper);
        if (one == null) {
            return new AuthUserBo();
        }
        return AuthUserBoConvert.INSTANCE.convertEntityToBo(one);
    }
}
